package com.rent.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.rent.constants.SysConstant;
import com.rent.exception.NbBaseException;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Objects;

/**
 * //JWT由三部分构成：header（头部）、payload（载荷）和signature（签名）
 * xxxxx.yyyyy.zzzzz
 * header:
 * header通常由两部分组成：令牌的类型（即JWT）和所使用的签名算法
 * json = {  "alg": "HS256", "typ": "JWT" }
 * Base64(json) = xxxxx
 * Payload:叫载荷 存放有效信息,它可以存放JWT提供的现成字段 :
 * iss: 该JWT的签发者。
 * sub: 该JWT所面向的用户。
 * aud: 接收该JWT的一方。
 * exp(expires): 什么时候过期，这里是一个Unix时间戳。
 * iat(issued at): 在什么时候签发的。
 * 例如：
 * json=         {
 * "iss": "www.baidu.com",
 * "sub": "you",
 * "aud": "me",
 * "name": "456",
 * "admin": true,
 * "iat": 1584091337,
 * "exp": 1784091337,
 * }
 * Base64(json) = yyyyyy
 * Signature签名，防止JWT内容被篡改
 * header中声明得签名算法 进行
 * HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret) = zzzzz
 * <p>
 * 如果我们想试验一下的话，可以在JWT的官网进行debugger。贴一下官网： https://jwt.io/
 * <p>
 * 什么时候应该使用JWT？
 * 授权：
 * 信息交换:JWT是在各方之间安全地传输信息的好方法。
 * 因为可以对JWT进行签名（例如，使用公钥/私钥对），
 * 所以您可以确定发件人是他们所说的人。
 * 此外，由于签名是使用标头和有效负载计算的，因此您还可以验证内容是否遭到篡改。
 */
@Slf4j
public class JwtUtil {

    // Token过期时间30分钟（用户登录过期时间是此时间的两倍，以token在reids缓存时间为准）
    public static final long EXPIRE_TIME = 60 * 60 * 1000 * 24 * 7;


    private static final String SECKET = "rent!#888";

    private static final String USERID = "userId";

    /**
     * 校验token是否正确
     *
     * @param token 密钥
     * @return 是否正确
     */
    public static boolean verify(String token) {
        try {
            // 根据密码生成JWT效验器
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECKET)).build();
            // 效验TOKEN
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }

    public static String getOpenId(String token) {
        try {
            return JWT.decode(token).getClaim(USERID).asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户名
     */
    public static Integer getUserId(String token) {
        try {
            return JWT.decode(token).getClaim(USERID).asInt();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 生成签名
     *
     * @param openId 用openId比较合适
     * @return 加密的token
     */
    public static String getJWT(String openId) {
        Date expire = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        return JWT.create()
                .withClaim(USERID, openId)
                .withExpiresAt(expire)
                .sign(Algorithm.HMAC256(SECKET));
    }

    /**
     * 生成签名
     *
     * @param userId 用户名
     * @return 加密的token
     */
    public static String getJWT(Integer userId) {
        Date expire = new Date(System.currentTimeMillis() + EXPIRE_TIME);
//		String token = JWT.create()
//				//.withAudience("audience") //观众，设置为userId
//				.withClaim(USERID, userId) //也可以在这设置userId
//				.withIssuedAt(new Date())
//				.withSubject("subject")
//				.withExpiresAt(expire)
//				.withJWTId("jtiid")
//				.sign(Algorithm.HMAC256(SECKET));

        return JWT.create()
                .withClaim(USERID, userId)
                .withExpiresAt(expire)
                .sign(Algorithm.HMAC256(SECKET));

    }

    /**
     * 根据request中的token获取用户账号
     * <p>
     * // * @param request
     *
     * @return
     * @throws NbBaseException
     */
    public static Integer getUserIdByToken(HttpServletRequest request) throws NbBaseException {
        String accessToken = request.getHeader(SysConstant.TOKEN);
        Integer userId = getUserId(accessToken);
        if (Objects.isNull(userId)) {
            throw new NbBaseException("未获取到用户userId");
        }
        return userId;
    }


    public static void main(String[] args) {

        //String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NjUzMzY1MTMsInVzZXJuYW1lIjoiYWRtaW4ifQ.xjhud_tWCNYBOg_aRlMgOdlZoWFFKB_givNElHNw3X0";

//		String token= JWT.create().withAudience("audience")
//				.withIssuedAt(new Date())
//				.withSubject("subject")
//				.withExpiresAt(new Date())
//				.withJWTId("jtiid")
//				.sign(Algorithm.HMAC256(SECKET));
//
//		//验证
//		//从jwt获取userId
//		try{
//			String userId = JWT.decode(token).getAudience().get(0);
//
//			String userId222 = JWT.decode(token).getClaims().get(USERID).asString();
//		}catch (JWTDecodeException e){
//			System.err.println("非法token！！！没有userId");
//			throw new RuntimeException("401");
//		}
//		//验证token
//		JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECKET)).build();
//		try{
//			jwtVerifier.verify(token);
//		}catch (JWTVerificationException e){
//			throw new RuntimeException("401");
//		}
//
//		String ooooo = getJWT("5a5f1de4-c4cc-4409-9fd3-98aaec0ab6ee");
//		System.err.println(ooooo);
//		System.err.println(verify(ooooo));

    }
}
